import 'dart:convert';

import 'package:dio/dio.dart';
import 'package:logger/logger.dart';
import 'package:vdrag_saas/config.dart';

/// 自定义异常
class AppException implements Exception {
  final String? _message;
  final int? _code;

  AppException([
    this._code,
    this._message,
  ]);

  @override
  String toString() {
    return "$_code$_message";
  }

  factory AppException.create(DioException error) {
    switch (error.type) {
      case DioExceptionType.cancel:
        {
          return BadRequestException(-1, "请求取消");
        }
      case DioExceptionType.connectionTimeout:
        {
          return BadRequestException(-1, "连接超时");
        }
      case DioExceptionType.sendTimeout:
        {
          return BadRequestException(-1, "请求超时");
        }
      case DioExceptionType.receiveTimeout:
        {
          return BadRequestException(-1, "响应超时");
        }
      case DioExceptionType.badResponse:
        {
          try {
            dynamic errCode = error.response?.statusCode;
            // String errMsg = error.response.statusMessage;
            // return ErrorEntity(code: errCode, message: errMsg);
            switch (errCode) {
              case 400:
                {
                  return BadRequestException(errCode, "请求语法错误");
                }
              case 401:
                {
                  return UnauthorisedException(errCode, "没有权限");
                }
              case 403:
                {
                  return UnauthorisedException(errCode, "服务器拒绝执行");
                }
              case 404:
                {
                  return UnauthorisedException(errCode, "无法连接服务器");
                }
              case 405:
                {
                  return UnauthorisedException(errCode, "请求方法被禁止");
                }
              case 500:
                {
                  return UnauthorisedException(errCode, "服务器内部错误");
                }
              case 502:
                {
                  return UnauthorisedException(errCode, "无效的请求");
                }
              case 503:
                {
                  return UnauthorisedException(errCode, "服务器挂了");
                }
              case 505:
                {
                  return UnauthorisedException(errCode, "不支持HTTP协议请求");
                }
              default:
                {
                  // return ErrorEntity(code: errCode, message: "未知错误");
                  return AppException(
                      errCode, error.response?.statusMessage ?? "未知错误");
                }
            }
          } on Exception catch (_) {
            return AppException(-1, "未知错误");
          }
        }
      default:
        {
          return AppException(-1, error.message ?? "未知错误");
        }
    }
  }
}

/// 请求错误
class BadRequestException extends AppException {
  BadRequestException(int code, String message) : super(code, message);
}

/// 未认证异常
class UnauthorisedException extends AppException {
  UnauthorisedException(int code, String message) : super(code, message);
}

/// 错误处理拦截器
class ErrorInterceptor extends Interceptor {
  @override
  void onError(DioException err, handler) {
    // error统一处理
    AppException appException = AppException.create(err);
    DioException error =
        DioException(error: appException, requestOptions: err.requestOptions);
    // 继续执行错误处理
    return handler.next(error);
  }
}

class Http {
  ///超时时间
  static const int CONNECT_TIMEOUT = 30000;
  static const int RECEIVE_TIMEOUT = 30000;
  late Dio dio;
  Http() {
    BaseOptions options = BaseOptions(
      connectTimeout: const Duration(milliseconds: CONNECT_TIMEOUT),

      // 响应流上前后两次接受到数据的间隔，单位为毫秒。
      receiveTimeout: const Duration(milliseconds: RECEIVE_TIMEOUT),
      baseUrl: HttpConfig.baseUrl,

      // Http请求头.
      headers: {},
    );

    dio = Dio(options);

    // 添加error拦截器
    dio.interceptors.add(ErrorInterceptor());
  }

  CancelToken _cancelToken = new CancelToken();

  /*
   * 取消请求
   *
   * 同一个cancel token 可以用于多个请求，当一个cancel token取消时，所有使用该cancel token的请求都会被取消。
   * 所以参数可选
   */
  void cancelRequests({CancelToken? token}) {
    token ?? _cancelToken.cancel("cancelled");
  }

  get(String url, {CancelToken? cancelToken}) async {
    Response response =
        await dio.get(url, cancelToken: cancelToken ?? _cancelToken);
    String str = response.toString();
    return jsonDecode(str);
  }

  post(String url, {data, CancelToken? cancelToken}) async {
    return (await dio.post(url,
            data: data, cancelToken: cancelToken ?? _cancelToken))
        .data;
  }

  put(String url, {data, CancelToken? cancelToken}) async {
    return await dio.put(url,
        data: data, cancelToken: cancelToken ?? _cancelToken);
  }
}
